﻿#include "../../../includes/multimedia/rtsp/crtspserver.h"
#include "../../../includes/multimedia/rtsp/crtspclient.h"
#include "../../../includes/QsLog/QsLog.h"
#include "../../../includes/common/common.h"
#include "../../../includes/common/NedAllocatorImpl.h"

//#pragma comment(lib,"../../../extends/libx264/lib/libx264.lib")

CRtspServer::CRtspServer(QObject *parent)
    : QTcpServer(parent),
      mimageBuffer(NULL)
{

}

CRtspServer::~CRtspServer()
{
    CloseServer();
    clearnH264();
}

/**
 * @brief CRtspServer::OpenServer 打开一个指定端口的服务器
 * @param port 端口号
 */
bool CRtspServer::OpenServer(int port)
{
    if(this->isListening() || port <= 0)
        return false;

    if (!this->listen(QHostAddress::Any, port))
    {
        emit sockLog("CRtspServer::OpenServer:"+
                        QString::asprintf("%d",port)+
                        " fail.");
        return false;
    }

    emit sockLog("CRtspServer::OpenServer:"+
                QString::asprintf("%d successed.",port));

    return true;
}

/**
 * @brief CRtspServer::CloseServer 关闭服务器
 */
void CRtspServer::CloseServer(void)
{
    emit sockLog(QString::fromLocal8Bit("服务器已经关闭."));

    this->close();

    deleteAllClients();
}

/**
 * @brief CRtspServer::addClientToGroup 添加一个客户端到群中
 * @param client
 * @return
 */
bool CRtspServer::addClientToGroup(CRtspClient *client)
{
    if(client == NULL) return false;

    QHash<QString, RtspGroup>::iterator itergroup = mGroups.find(client->getSuffix());
    if(itergroup != mGroups.end())
    {
        if(client->getConnectionMode() == RTSP_PUSHER)
        {
            QList<CRtspClient*>::iterator iterclient = qFind(itergroup.value().clients.begin(),
                                                             itergroup.value().clients.end(),
                                                             client);
            if(iterclient != itergroup.value().clients.end())
            {
                itergroup.value().clients.erase(iterclient);
            }

            itergroup.value().pusher = client;
        }
        else
        {
            QList<CRtspClient*>::iterator iterclient = qFind(itergroup.value().clients.begin(),
                                                             itergroup.value().clients.end(),
                                                             client);
            if(iterclient != itergroup.value().clients.end())
                return false;

            itergroup.value().clients.push_back(client);
        }
    }
    else
    {
        if(client->getConnectionMode() == RTSP_PUSHER)
        {
            mGroups[client->getSuffix()].pusher = client;
        }
        else
        {
            QList<CRtspClient*> pClients = mGroups[client->getSuffix()].clients;
            QList<CRtspClient*>::iterator iterclient = qFind(pClients.begin(),
                                                             pClients.end(),
                                                             client);
            if(iterclient == pClients.end())
                pClients.push_back(client);
        }
    }

    return true;
}

void CRtspServer::sockConnectSlot(qintptr conn)
{
    emit sockLog(QString::asprintf("%lld", static_cast<qint64>(conn))+
                 QString::fromLocal8Bit("到达."));
}

void CRtspServer::sockDisConnectSlot(qintptr conn)
{
    emit sockLog(QString::asprintf("%lld",static_cast<qint64>(conn))+
                 QString::fromLocal8Bit("离开."));

    deleteClient(conn);
}

/**
 * @brief CRtspServer::sockBinMessageSlot 处理网络二进制消息
 * @param conn
 * @param data
 */
void CRtspServer::sockBinMessageSlot(qintptr conn,QByteArray data)
{  

}

/**
 * @brief CRtspServer::sockLogSlot 日志消息
 * @param log
 */
void CRtspServer::sockLogSlot(QString log)
{

}

/**
 * @brief CRtspServer::deleteClient 清除指定的客户端
 * @param socketDescriptor
 */
void CRtspServer::deleteClient(qintptr socketDescriptor)
{
    QMutexLocker locker(&mclientMutex);

    QHash<qintptr, CRtspClient*>::iterator iter = mtcpClients.find(socketDescriptor);
    if(iter == mtcpClients.end())
        return;

    // 从群里删除这个客户端
    QHash<QString, RtspGroup>::iterator itergroup = mGroups.find(iter.value()->getSuffix());
    if(itergroup != mGroups.end())
    {
        if(itergroup.value().pusher == iter.value())
        {
            itergroup.value().pusher = NULL;
        }
        else
        {
            QList<CRtspClient*>::iterator iterclient = qFind(itergroup.value().clients.begin(),
                                                             itergroup.value().clients.end(),
                                                             iter.value());
            if(iterclient != itergroup.value().clients.end())
                itergroup.value().clients.erase(iterclient);
        }

        if(itergroup.value().pusher == NULL &&
           itergroup.value().clients.isEmpty())
        {
            mGroups.erase(itergroup);
        }
    }

    disconnect(iter.value(),&CRtspClient::sockLog,
            this,&CRtspServer::sockLogSlot);
    disconnect(iter.value(),&CRtspClient::sockDisConnect,
            this,&CRtspServer::sockDisConnectSlot);
    disconnect(iter.value(),&CRtspClient::signalsNetBinary,
            this,&CRtspServer::sockBinMessageSlot);

    iter.value()->deleteLater();
    mtcpClients.erase(iter);
}

/**
 * @brief CRtspServer::initH264 初始化h264
 */
void CRtspServer::initH264(QSize screenSize)
{
    m_contextSize = screenSize;
    m_iNal = 0;
    m_Nals = NULL;
    m_Handle = NULL;
    m_Pic_in = (x264_picture_t*)allocBytes(sizeof(x264_picture_t));
    m_Pic_out = (x264_picture_t*)allocBytes(sizeof(x264_picture_t));
    m_Param = (x264_param_t*)allocBytes(sizeof(x264_param_t));

    x264_param_default(m_Param);   //给参数结构体赋默认值
    x264_param_default_preset(m_Param, "fast" , "zerolatency" );  //设置preset和tune

    //修改部分参数
    m_Param->i_csp=X264_CSP_I420;
    m_Param->i_width   = screenSize.width();   // 宽度
    m_Param->i_height  = screenSize.height();  // 高度
    m_Param->i_fps_num  = 25;     // 设置帧率（分子）
    m_Param->i_fps_den  = 1;      // 设置帧率时间1s（分母）

    m_Param->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;
    m_Param->i_keyint_max = 10;              //在此间隔设置IDR关键帧

    m_Param->rc.i_bitrate = 1200;       // 设置码率,在ABR(平均码率)模式下才生效，且必须在设置ABR前先设置bitrate
    m_Param->rc.i_rc_method = X264_RC_ABR;  // 码率控制方法，CQP(恒定质量)，CRF(恒定码率,缺省值23)，ABR(平均码率)

    //set profile
    x264_param_apply_profile(m_Param, "baseline");

    //open encoder
    m_Handle = x264_encoder_open(m_Param);

    x264_picture_init(m_Pic_out);
    x264_picture_alloc(m_Pic_in, X264_CSP_I420, m_Param->i_width, m_Param->i_height);
    m_Pic_in->i_pts=0;

    m_baseFrameSize=screenSize.width()*screenSize.height();
    mimageBuffer=(quint8*)allocBytes(screenSize.width()*screenSize.height()*3);

    m_SwsContext= sws_getContext(screenSize.width(), screenSize.height(),
                                 m_srcFormat,
                                 screenSize.width(), screenSize.height(),
                                 AV_PIX_FMT_YUV420P,
                                 SWS_BILINEAR, NULL, NULL, NULL);

    int ret;
    if ((ret = av_image_alloc(src_data, src_linesize,
            screenSize.width(), screenSize.height(), m_srcFormat, 8)) < 0)
    {
        qDebug()<<"av_image_alloc failed.";
    }
}

/**
 * @brief CRtspServer::clearnH264 卸载h264
 */
void CRtspServer::clearnH264(void)
{
    if(m_Pic_in != NULL)
        x264_picture_clean(m_Pic_in);
    if(m_Handle != NULL)
        x264_encoder_close(m_Handle);
    m_Handle = NULL;

    if(m_Pic_in != NULL)
        deallocBytes(m_Pic_in);
    if(m_Pic_out != NULL)
        deallocBytes(m_Pic_out);
    if(m_Param != NULL)
        deallocBytes(m_Param);

    if(m_SwsContext)
    {
        av_freep(&src_data[0]);
        sws_freeContext(m_SwsContext);
        m_SwsContext = NULL;
    }

    if(mimageBuffer)
        deallocBytes(mimageBuffer);
    mimageBuffer=NULL;
}

/**
 * @brief CRtspServer::HandleImage 处理图片
 * @param image
 * @return
 */
bool CRtspServer::HandleImage(QImage& image)
{
    if(mimageBuffer == NULL || image.isNull())
        return false;

    memcpy(mimageBuffer,image.scaled(m_contextSize.width(), m_contextSize.height(),
                 Qt::IgnoreAspectRatio, Qt::SmoothTransformation)
            .convertToFormat(QImage::Format_RGB888).constBits(),
           m_contextSize.width()*m_contextSize.height()*3);

    return HandleYuv240PFrame(mimageBuffer);
}

/**
 * @brief CRtspServer::HandleYuv240PFrame 处理YUV240P数据
 * @param yuvData
 * @return
 */
bool CRtspServer::HandleYuv240PFrame(unsigned char* yuvData)
{
    if(m_Handle == NULL || yuvData == NULL)
        return false;

    memcpy(src_data[0],yuvData,m_baseFrameSize*3);

    sws_scale(m_SwsContext,
              src_data,src_linesize,
              0,m_contextSize.height(),
              m_Pic_in->img.plane,
              m_Pic_in->img.i_stride);

    int ret = x264_encoder_encode(m_Handle, &m_Nals, &m_iNal,m_Pic_in, m_Pic_out);
    if (ret< 0)
        return false;

    for (int j = 0; j < m_iNal; ++j)
    {
        AVFrame videoFrame = {0};
        videoFrame.type = 0;
        videoFrame.size = m_Nals[j].i_payload;
        videoFrame.timestamp = H264Source::GetTimestamp();
        videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
        memcpy(videoFrame.buffer.get(), m_Nals[j].p_payload, videoFrame.size);

        HandleFrame(&videoFrame);
    }

    return true;
}

/**
 * @brief CRtspServer::HandleFrame 处理视频帧
 * @param frame
 * @return
 */
bool CRtspServer::HandleFrame(AVFrame *frame)
{
    if(frame == NULL)
        return false;

    QMutexLocker locker(&mclientMutex);

    QHash<qintptr, CRtspClient*>::iterator iter = mtcpClients.begin();
    for(;iter != mtcpClients.end();++iter)
    {
        iter.value()->HandleFrame(frame);
    }
}

/**
 * @brief CRtspServer::HandleFrameGroup 处理视频帧到群
 * @param suffix
 * @param frame
 * @return
 */
bool CRtspServer::HandleFrameGroup(QString suffix,QByteArray* frame)
{
    if(suffix == "" || frame == NULL)
        return false;

    //QMutexLocker locker(&mclientMutex);

    QHash<QString, RtspGroup>::iterator itergroup = mGroups.find(suffix);
    if(itergroup != mGroups.end())
    {
        QList<CRtspClient*>::iterator iterclient = itergroup.value().clients.begin();
        for(;iterclient != itergroup.value().clients.end();++iterclient)
        {
            (*iterclient)->sendUdpData2(frame);
        }
    }

    return true;
}

/**
 * @brief CRtspServer::deleteAllClients 清除所有的客户端
 */
void CRtspServer::deleteAllClients(void)
{
    QMutexLocker locker(&mclientMutex);

    QHash<qintptr, CRtspClient*>::iterator iter = mtcpClients.begin();
    for(;iter != mtcpClients.end();++iter)
    {
        disconnect(iter.value(),&CRtspClient::sockLog,
                this,&CRtspServer::sockLogSlot);
        disconnect(iter.value(),&CRtspClient::sockDisConnect,
                this,&CRtspServer::sockDisConnectSlot);
        disconnect(iter.value(),&CRtspClient::signalsNetBinary,
                this,&CRtspServer::sockBinMessageSlot);

        iter.value()->deleteLater();
    }

    mtcpClients.clear();
    mGroups.clear();
}

void CRtspServer::incomingConnection(qintptr socketDescriptor)
{
    QMutexLocker locker(&mclientMutex);

    CRtspClient* tmpClient = new CRtspClient(this,
                                             socketDescriptor);
    tmpClient->setRtspServer(this);

    mtcpClients[socketDescriptor] = tmpClient;

    connect(tmpClient,&CRtspClient::sockLog,
            this,&CRtspServer::sockLogSlot,
            Qt::QueuedConnection);
    connect(tmpClient,&CRtspClient::sockDisConnect,
            this,&CRtspServer::sockDisConnectSlot,
            Qt::QueuedConnection);
    connect(tmpClient,&CRtspClient::signalsNetBinary,
            this,&CRtspServer::sockBinMessageSlot,
            Qt::QueuedConnection);

    sockConnectSlot(socketDescriptor);
}
